package org.tagging.service.impl.other;

import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.tagging.dao.TaggingUserMapper;
import org.tagging.exception.UnSupportedLanguageException;
import org.tagging.exception.UsernameAlreadyExistException;
import org.tagging.model.*;
import org.tagging.utils.Asserts;
import org.tagging.utils.RoleEnum;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
//@Transactional
//@EnableCaching
public class ClientUserServiceImpl implements UserDetailsService {
    @Resource
    private TaggingUserMapper userMapper;
    @Autowired
    private AuthorityServiceImpl authorityService;
    @Value("${password.prefix:{bcrypt}}")
    private String passwordPrefix;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RoleServiceImpl roleService;

    @Autowired
    private AuthorityUserServiceImpl authorityUserService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        TaggingUser user = queryByUsername(username, TaggingUser.Column.id, TaggingUser.Column.username, TaggingUser.Column.password, TaggingUser.Column.role);
        Asserts.userNotNull(user, "用户名不存在！");
        List<TaggingAuthority> taggingAuthorities = authorityService.retrieveAuthoritiesByRoleId(user.getRole());
        List<GrantedAuthority> authorityList = new ArrayList<>(taggingAuthorities.size());
        TaggingRole taggingRole = roleService.queryById(user.getRole(), TaggingRole.Column.id, TaggingRole.Column.name);
        authorityList.add(new SimpleGrantedAuthority("ROLE_" + taggingRole.getName()));
        for (TaggingAuthority taggingAuthority : taggingAuthorities) {
            authorityList.add(new SimpleGrantedAuthority(taggingAuthority.getAuthority()));
        }

        List<TaggingUserAuthority> taggingUserAuthorities = authorityUserService.queryByUserId(user.getId());//当前用户所拥有的个人权限
        for (TaggingUserAuthority taggingUserAuthority : taggingUserAuthorities) {
            authorityList.add(new SimpleGrantedAuthority(taggingUserAuthority.getAuthority()));
        }
        //注意，此处如果是角色，需要添加前缀ROLE_
//        return new User(username, passwordPrefix + user.getPassword(), authorityList);
        return new User(username, user.getPassword(), authorityList);
    }

    public TaggingUser queryByUsername(String username, TaggingUser.Column... columns) {
        TaggingUserExample taggingUserExample = new TaggingUserExample();
        TaggingUserExample.Criteria criteria = taggingUserExample.createCriteria();
        criteria.andUsernameEqualTo(username);
        return userMapper.selectOneByExampleSelective(taggingUserExample, columns);
    }

    public int addClientUser(String username, String password) throws UsernameAlreadyExistException {
        TaggingUser user = new TaggingUser();
        user.setPassword(passwordEncoder.encode(password));
        user.setUsername(username);
        user.setRole(RoleEnum.USER.value());
        return insertSelective(user);
    }

    private int insertSelective(TaggingUser user) throws UsernameAlreadyExistException {
        String username = user.getUsername();
        if (StringUtils.hasText(username)) {
            TaggingUser u = queryByUsername(username);
            Asserts.userNull(u, "username already exist!");
        }
        return userMapper.insertSelective(user);
    }

    public User retrieveCurrentUser() {
        return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }

    public TaggingUser retrieveCurrentUserId(User user) {
        return queryByUsername(user.getUsername(), TaggingUser.Column.id);
    }

    public Integer retrieveCurrentUserId() {
        return retrieveCurrentUserId(retrieveCurrentUser()).getId();
    }

    public void resetPassword(String username, String password) {
        TaggingUser user = new TaggingUser();
        user.setPassword(passwordEncoder.encode(password));
        user.setUsername(username);
        TaggingUserExample example = new TaggingUserExample();
        TaggingUserExample.Criteria criteria = example.createCriteria();
        criteria.andUsernameEqualTo(username);
        userMapper.updateByExampleSelective(user, example);
    }


    private TaggingUser queryId(Integer userId, TaggingUser.Column... columns) {
        return userMapper.selectByPrimaryKeySelective(userId, columns);
    }

    public void clearCompleteToday() {
        TaggingUserExample example = new TaggingUserExample();
        List<TaggingUser> taggingUsers = userMapper.selectByExampleSelective(example, TaggingUser.Column.id);
        for (TaggingUser taggingUser : taggingUsers) {
            taggingUser.setMalayCompleteToday(0);
            taggingUser.setIndonesiaCompleteToday(0);
            userMapper.updateByPrimaryKeySelective(taggingUser);
        }
    }

    public void updateLastLoginTime(String username) {
        TaggingUser user = queryByUsername(username, TaggingUser.Column.id);
        user.setLastLoginTime(LocalDateTime.now());
        userMapper.updateByPrimaryKeySelective(user);
    }

    public void incrementComplete(String language) throws UnSupportedLanguageException {
        Integer userId = retrieveCurrentUserId();
        TaggingUser user = queryId(userId, TaggingUser.Column.id, TaggingUser.Column.malayCompleteToday, TaggingUser.Column.indonesiaCompleteToday, TaggingUser.Column.malayTotal, TaggingUser.Column.indonesiaTotal);
        switch (language) {
            case "indonesian": {
                user.setIndonesiaCompleteToday(user.getIndonesiaCompleteToday() + 1);
                user.setIndonesiaTotal(user.getIndonesiaTotal() + 1);
                break;
            }
            case "malay": {
                user.setMalayTotal(user.getMalayTotal() + 1);
                user.setMalayCompleteToday(user.getMalayCompleteToday() + 1);
                break;
            }
            case "philippines": {
                user.setPhilippinesTotal(user.getPhilippinesTotal() + 1);
                user.setPhilippinesCompleteToday(user.getPhilippinesCompleteToday() + 1);
                break;
            }
            default:{
                throw new UnSupportedLanguageException("language:"+language+" is not supported!");
            }
        }
        userMapper.updateByPrimaryKeySelective(user);
    }

    public List<TaggingUser> querySelective(TaggingUser.Column... columns) {
        TaggingUserExample example = new TaggingUserExample();
        TaggingUserExample.Criteria criteria = example.createCriteria();
        criteria.andRoleEqualTo(RoleEnum.USER.value());
        return userMapper.selectByExampleSelective(example, columns);
    }

    public List<TaggingUser> querySelectiveWithPagination(Integer page, Integer pageSize, TaggingUser.Column... columns) {
        TaggingUserExample example = new TaggingUserExample();
        TaggingUserExample.Criteria criteria = example.createCriteria();
        criteria.andRoleEqualTo(RoleEnum.USER.value());
        PageHelper.startPage(page, pageSize);
        return userMapper.selectByExampleSelective(example, columns);
    }

    public Integer queryCount() {
        TaggingUserExample example = new TaggingUserExample();
        return (int) userMapper.countByExample(example);
    }
}
